/*
 * Copyright (C) 2010 mAPPn.Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mol.market.common.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.net.URLEncoder;
import java.util.concurrent.RejectedExecutionException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.protocol.HTTP;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Debug;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;

import com.mol.market.R;
import com.mol.market.Session;
import com.mol.market.common.network.AndroidHttpClient;
import com.mol.market.common.network.HttpClientFactory;
import com.mol.market.common.widget.LoadingDrawable;
import com.mol.market.demo.widget.CornerMark;

/**
 * 本类提供关于图片下载的一些工具方法
 *
 * @author andrew
 * @date 2011-3-21
 */
public class ImageUtils {


  public static Bitmap getImageFromUrl(Context context, String url, boolean isCompressed) {

    if (TextUtils.isEmpty(url)) {
      return null;
    }
    HttpGet httpRequest = null;
    try {
      int pos = url.lastIndexOf("/");
      String prefix = url.substring(0, pos);
      String fileName = url.substring(pos);
      String encodeName = URLEncoder.encode(fileName, HTTP.UTF_8);
      String encodeUrl = prefix + encodeName;
      httpRequest = new HttpGet(encodeUrl);
    } catch (UnsupportedEncodingException e) {
      Utils.E("Error when parsing url", e);
      return null;
    }
    ;
    HttpResponse response = null;
    AndroidHttpClient client = HttpClientFactory.get().getHttpClient();
    try {
      response = client.execute(httpRequest);
      final int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode != HttpStatus.SC_OK) {
        Utils.W("Error " + statusCode + " while retrieving bitmap from "
            + url);
        return null;
      }
      HttpEntity entity = response.getEntity();
      if (entity != null) {
        InputStream inputStream = null;
        try {
          inputStream = entity.getContent();

          // non-compressed images no need to be cached to the sd-card
          BitmapFactory.Options o = new BitmapFactory.Options();
          o.inPurgeable = true;
          o.inInputShareable = true;
          Bitmap bmp = BitmapFactory.decodeStream(new FlushedInputStream(inputStream),
              null, o);
          return bmp;
        } finally {
          if (inputStream != null) {
            inputStream.close();
          }
          entity.consumeContent();
        }
      }
    } catch (ClientProtocolException e) {
      Utils.W("ClientProtocolException " + url, e);
    } catch (IOException e) {
      Utils.W("IOException " + url, e);
    } catch (Exception e) {
      Utils.W("other exception when download images from " + url, e);
    } catch (OutOfMemoryError err) {
      Utils.W("OutOfMemoryError when download images from " + url, err);
    } finally {
      httpRequest.abort();
    }
    return null;
  }

  /**
   * 判断是否内存够用
   */
  private static boolean isNoMoreMemory(Context context) {

    // 已经使用的内存大小
    long allocNativeHeap = Debug.getNativeHeapAllocatedSize();
    // 可用的栈内存大小
    long maxVmHeap = Debug.getNativeHeapSize();
    // 可用的总内存大小
    long maxMemory = Runtime.getRuntime().maxMemory();
    // 内存溢出阈值（3M）
    int heapPad = 3145728;

    if (maxVmHeap + heapPad < maxMemory) {
      return false;
    }

    if ((allocNativeHeap + heapPad) >= maxVmHeap) {
      CacheManager.getInstance(context).clearFromMemory(context);
      System.gc();
      return true;
    }
    return false;
  }

  static class DrawableDownloaderTask extends AsyncTaskEx<Object, Void, Drawable> {

    private       Context                  context;

    private final WeakReference<ImageView> imageViewReference;

    public DrawableDownloaderTask(ImageView imageView) {
      imageViewReference = new WeakReference<ImageView>(imageView);
    }


    @Override
    protected Drawable doInBackground(Object... params) {
      context = (Context) params[0];
      CacheManager cache = CacheManager.getInstance(context);
      String pkgName = (String) params[1];
      PackageManager pm = context.getPackageManager();

      PackageInfo info = null;
      try {
        info = pm.getPackageInfo(pkgName, 0);
      } catch (NameNotFoundException e) {
        e.printStackTrace();
      }

      if (info == null) {
        return null;
      }
      Drawable d = info.applicationInfo.loadIcon(pm);

      if (d instanceof BitmapDrawable) {
        Bitmap b = ((BitmapDrawable) d).getBitmap();
        cache.cacheDrawable(context, pkgName, b);
      }
      return d;
    }

    @Override
    protected void onPostExecute(Drawable d) {
      if (isCancelled()) {
        d = null;
      }

      if (imageViewReference != null) {
        ImageView imageView = imageViewReference.get();
        DrawableDownloaderTask drawableDownloaderTask = getBitmapDownloaderTask3(imageView);

        // Change bitmap only if this process is still associated with
        // it
        if (this == drawableDownloaderTask && d != null) {

          Drawable drawable = imageView.getDrawable();
          if (drawable != null) {
            drawable.setCallback(null);
          }

          imageView.setImageDrawable(d);
          imageView.startAnimation(AnimationUtils.loadAnimation(context, R.anim.show_in));
        }
      }
    }
  }

  public static final int TYPE_NORAML      = 1;
  public static final int TYPE_IMAGE       = 2;
  public static final int TYPE_SCREENSHOT  = 3;
  public static final int TYPE_TOP         = 4;
  public static final int TYPE_CPA         = 5;
  public static final int TYPE_PAUSE_MASK  = 6;
  public static final int TYPE_CORNER_MARK = 7;

  static class BitmapDownloaderTask extends AsyncTaskEx<Object, Void, Bitmap> {
    private       Context                  context;
    private       String                   url;

    private final WeakReference<ImageView> imageViewReference;
    private       int                      type;
    
    private       Object[]                 extra;

    public BitmapDownloaderTask(ImageView imageView) {
      imageViewReference = new WeakReference<ImageView>(imageView);
    }


    @Override
    // Actual download method, run in the task thread
    protected Bitmap doInBackground(Object... params) {
      // params comes from the execute() call: params[0] is the url.
      context = (Context) params[0];
      url = (String) params[1];
      type = (Integer) params[2];
      
      if(params.length > 3){
          extra = (Object[])params[3];
      }
      
      CacheManager cache = CacheManager.getInstance(context);

      Bitmap bmp = null;
      String cacheKey = url;
      if (imageViewReference != null) {
        ImageView imageView = imageViewReference.get();
        if (imageView != null) {
          if (imageView.getId() == R.id.iv_user_icon) {
            cacheKey = url + String.valueOf(R.id.iv_user_icon);
          } else if (imageView.getId() == R.id.home_gallery_user) {
            cacheKey = url + String.valueOf(R.id.home_gallery_user);
          }
        }
      }
      // 当已经缓存过，尝试从SD卡重新加载图片
      if (type == TYPE_TOP) {
        bmp = getDrawableFromFile(context, cacheKey);
      } else if (cache.existsDrawable(cacheKey)) {

        if (isNoMoreMemory(context)) {
          // 检查内存情况，避免内存溢出
          return null;
        }
        if (type == TYPE_SCREENSHOT || type == TYPE_CPA) {
          bmp = getBitmapFromSdcard(context, cacheKey, true);
        } else {
          bmp = getBitmapFromSdcard(context, cacheKey, false);
        }
      }

      // 图片需要从网络加载
      if (bmp == null) {
        if (type == TYPE_SCREENSHOT || type == TYPE_CPA) {
          if (isNoMoreMemory(context)) {
            // 检查内存情况，避免内存溢出
            return null;
          }
          bmp = getImageFromUrl(context, url, true);
        } else {
          bmp = getImageFromUrl(context, url, false);
        }

        // 头像遮罩处理
        if (imageViewReference != null) {
          ImageView imageView = imageViewReference.get();
          if (imageView != null && bmp != null) {
            if (imageView.getId() == R.id.iv_user_icon) {
              bmp = createUserIcon(context, bmp);
            } else if (imageView.getId() == R.id.home_gallery_user) {
              bmp = createHomeUserIcon(context, bmp);
            }
          }
        }

        if (bmp != null) {

          if (type == TYPE_IMAGE || type == TYPE_SCREENSHOT ||
              type == TYPE_CPA) {
            cache.cacheDrawableToL2(context, cacheKey, bmp);
            return bmp;
          } else if (type == TYPE_TOP) {
            cache.cacheDrawableToFile(context, cacheKey, bmp);
            return bmp;
          }

          if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            if (imageView != null) {

              int id = imageView.getId();
              if (id == R.id.iv_user_icon || id == R.id.home_gallery_user) {
                cache.cacheDrawable(context, cacheKey, bmp);
                return bmp;
              }
            }
          }
        }
      }
      cache.cacheDrawable(context, cacheKey, bmp);
      return bmp;
    }

    @Override
    // Once the image is downloaded, associates it to the imageView
    protected void onPostExecute(Bitmap bitmap) {
      if (isCancelled()) {
        bitmap = null;
      }

      if (imageViewReference != null) {
        ImageView imageView = imageViewReference.get();
        BitmapDownloaderTask bitmapDownloaderTask;
        if (type == TYPE_IMAGE) {
          bitmapDownloaderTask = getBitmapDownloaderTask2(imageView);
        } else {
          bitmapDownloaderTask = getBitmapDownloaderTask1(imageView);
        }

        // Change bitmap only if this process is still associated with
        // it
        if (this == bitmapDownloaderTask && bitmap != null) {
          Drawable drawable = imageView.getDrawable();
          if (drawable != null) {
            drawable.setCallback(null);
          }
          if (type == TYPE_IMAGE) {

            imageView.setBackgroundDrawable(null);
            imageView.setImageBitmap(scaleBitmap(context, rotateImage(bitmap)));

          } else if (type == TYPE_SCREENSHOT) {

            imageView.setImageBitmap(rotateImage(bitmap));

          } else if (type == TYPE_CPA) {

            imageView.setImageBitmap(bitmap);

          } else if (type == TYPE_TOP) {

            BitmapDrawable background = new BitmapDrawable(bitmap);
            StateListDrawable foreground = getMaskDrawable(context);
            imageView.setImageDrawable(foreground);
            imageView.setBackgroundDrawable(background);
          } else if (type == TYPE_PAUSE_MASK) {

            imageView.setImageBitmap(maskPauseIcon(context, bitmap));

          } else if (type == TYPE_CORNER_MARK){
              
            CornerMark mark = null;  
              
            if(extra != null && extra.length > 0){
                Object obj = extra[0];
                if(obj != null && obj instanceof CornerMark){
                    mark = (CornerMark) obj;
                }
            }
            
            imageView.setImageBitmap(maskCorner(context, bitmap, mark));
              
          } else {
            imageView.setImageBitmap(bitmap);
          }
          imageView.startAnimation(AnimationUtils.loadAnimation(context, R.anim.show_in));
        }
      }
    }
  }

  static class DownloadedDrawable1 extends BitmapDrawable {

    private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference1;

    public DownloadedDrawable1(Drawable defaultBitmap, BitmapDownloaderTask bitmapDownloaderTask) {
      super(((BitmapDrawable) defaultBitmap).getBitmap());
      bitmapDownloaderTaskReference1 = new WeakReference<BitmapDownloaderTask>(
          bitmapDownloaderTask);
    }

    public BitmapDownloaderTask getBitmapDownloaderTask() {
      return bitmapDownloaderTaskReference1.get();
    }
  }

  static class DownloadedDrawable3 extends BitmapDrawable {

    private final WeakReference<DrawableDownloaderTask> bitmapDownloaderTaskReference3;

    public DownloadedDrawable3(Drawable defaultBitmap,
        DrawableDownloaderTask bitmapDownloaderTask) {
      super(((BitmapDrawable) defaultBitmap).getBitmap());
      bitmapDownloaderTaskReference3 = new WeakReference<DrawableDownloaderTask>(
          bitmapDownloaderTask);
    }

    public DrawableDownloaderTask getBitmapDownloaderTask() {
      return bitmapDownloaderTaskReference3.get();
    }
  }

  static class DownloadedDrawable2 extends AnimationDrawable {

    private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference2;

    public DownloadedDrawable2(Drawable defaultAnimation,
        BitmapDownloaderTask bitmapDownloaderTask) {
      AnimationDrawable drawable = ((AnimationDrawable) defaultAnimation);
      final int frameCounter = drawable.getNumberOfFrames();
      for (int i = 0; i < frameCounter; i++) {
        super.addFrame(drawable.getFrame(i), drawable.getDuration(i));
      }
      super.setOneShot(false);
      bitmapDownloaderTaskReference2 = new WeakReference<BitmapDownloaderTask>(
          bitmapDownloaderTask);
    }

    public BitmapDownloaderTask getBitmapDownloaderTask() {
      return bitmapDownloaderTaskReference2.get();
    }
  }

  // fetch normal task

  private static BitmapDownloaderTask getBitmapDownloaderTask1(ImageView imageView) {
    if (imageView != null) {
      Drawable drawable = imageView.getDrawable();
      if (drawable == null || !(drawable instanceof DownloadedDrawable1)) {
        return null;
      }
      DownloadedDrawable1 downloadedDrawable = (DownloadedDrawable1) drawable;
      return downloadedDrawable.getBitmapDownloaderTask();
    }
    return null;
  }

  // fetch animation task

  private static BitmapDownloaderTask getBitmapDownloaderTask2(ImageView imageView) {
    if (imageView != null) {
      Drawable drawable = imageView.getBackground();
      if (drawable == null || !(drawable instanceof DownloadedDrawable2)) {
        return null;
      }
      DownloadedDrawable2 downloadedDrawable = (DownloadedDrawable2) drawable;
      return downloadedDrawable.getBitmapDownloaderTask();
    }
    return null;
  }

  // fetch animation task

  private static DrawableDownloaderTask getBitmapDownloaderTask3(ImageView imageView) {
    if (imageView != null) {
      Drawable drawable = imageView.getDrawable();
      if (drawable == null || !(drawable instanceof DownloadedDrawable3)) {
        return null;
      }
      DownloadedDrawable3 downloadedDrawable = (DownloadedDrawable3) drawable;
      return downloadedDrawable.getBitmapDownloaderTask();
    }
    return null;
  }

  /**
   * 下载产品列表的ICON
   */
  public static void download(Context context, String url,
      ImageView imageView, boolean isMask) {

    download(context, url, imageView, R.drawable.loading_icon, false, isMask);
  }

  /**
   * 下载已经安装应用的ICON
   */
  public static void download(Context context, String packageName, ImageView v, int res) {

    CacheManager cache = CacheManager.getInstance(context);
    Bitmap bmp = cache.getDrawableFromCache(context, packageName);
    if (bmp != null) {
      v.setImageBitmap(bmp);
      return;
    }

    Drawable defaultDrawable = context.getResources().getDrawable(res);
    Drawable drawable = v.getDrawable();
    if (drawable != null) {
      drawable.setCallback(null);
    }
    v.setImageDrawable(defaultDrawable);

    Session session = Session.get(context);
    if (session.isStopDownloadImage()) {
      v.setVisibility(View.GONE);
      return;
    } else {
      v.setVisibility(View.VISIBLE);
    }

    if (cancelPotentialBitmapDownload(packageName, v)) {
      DrawableDownloaderTask task = new DrawableDownloaderTask(v);
      DownloadedDrawable3 downloadedDrawable = new DownloadedDrawable3(defaultDrawable, task);
      v.setImageDrawable(downloadedDrawable);
      try {
        task.execute(context, packageName);
      } catch (RejectedExecutionException e) {
        Utils.E("RejectedExecutionException when download image", e);
      }
    }
  }
  
  public static void download(Context context, String url, ImageView imageView, int res,
          boolean isReserved, boolean isMask){
        download(context, url, imageView, res, isReserved, false, TYPE_NORAML);
  }

  /**
   * 下载产品列表的ICON
   *
   * @param isMask 是否使用暂停遮罩
   */
  public static void download(Context context, String url, ImageView imageView, int res,
      boolean isReserved, boolean isMask,int type,Object... extra) {

    CacheManager cache = CacheManager.getInstance(context);
    
    Bitmap bmp;
    if (imageView.getId() == R.id.iv_user_icon) {
      bmp = cache.getDrawableFromCache(context, url + String.valueOf(R.id.iv_user_icon));
    } else if (imageView.getId() == R.id.home_gallery_user) {
      bmp = cache.getDrawableFromCache(context, url + String.valueOf(R.id.home_gallery_user));
    } else {
      bmp = cache.getDrawableFromCache(context, url);
    }
    
    Drawable old = imageView.getDrawable();
    if (old != null) {
      old.setCallback(null);
    }

    if (bmp != null) {
      if (isMask) {
        imageView.setImageBitmap(maskPauseIcon(context, bmp));
      } else if ( type == TYPE_CORNER_MARK){
        //FIXME 最好将图片处理以后的结果缓存起来，而不是缓存原始图片.频繁的处理图片
        //      会损失部分性能
        /**
         * @unused 暂时不在Icon上加角标
         */
        imageView.setImageBitmap(maskCorner(context, bmp, (CornerMark)extra[0]));
      }else {
        imageView.setImageBitmap(bmp);
      }
      
      return;
    }
    Drawable defaultDrawable = context.getResources().getDrawable(res);
    imageView.setImageDrawable(defaultDrawable);

    Session session = Session.get(context);
    if (session.isStopDownloadImage()) {
      if (isReserved) {
        imageView.setVisibility(View.VISIBLE);
        imageView.setImageResource(res);
      } else {
        imageView.setVisibility(View.GONE);
      }
      return;
    } else {
      imageView.setVisibility(View.VISIBLE);
    }
    

    if (cancelPotentialBitmapDownload(url, imageView)) {
      BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
      if (defaultDrawable == null) {
        return;
      }
      DownloadedDrawable1 downloadedDrawable = new DownloadedDrawable1(defaultDrawable, task);
      imageView.setImageDrawable(downloadedDrawable);
      try {
        task.execute(context, url, type, extra);
      } catch (RejectedExecutionException e) {
        Utils.E("RejectedExecutionException when download image", e);
      }
    }
  }

  /**
   * 下载首页的顶部推荐图
   */
  public static void downloadHomeTopDrawable(Context context, String url, ImageView imageView) {

    Session session = Session.get(context);
    if (session.isStopDownloadImage()) {
      return;
    }

    CacheManager cache = CacheManager.getInstance(context);
    Bitmap bmp = cache.getDrawableFromCache(context, url);
    if (bmp != null) {
      BitmapDrawable background = new BitmapDrawable(bmp);
      StateListDrawable foreground = getMaskDrawable(context);
      imageView.setImageDrawable(foreground);
      imageView.setBackgroundDrawable(background);
      return;
    }

    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inPurgeable = true;
    o.inInputShareable = true;
    BitmapDrawable defaultDrawable = new BitmapDrawable(BitmapFactory.decodeResource(
        context.getResources(), R.drawable.banner_loading, o));
    if (cancelPotentialBitmapDownload(url, imageView)) {
      BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
      DownloadedDrawable1 downloadedDrawable = new DownloadedDrawable1(defaultDrawable, task);
      imageView.setImageDrawable(downloadedDrawable);
      try {
        task.execute(context, url, TYPE_TOP);
      } catch (RejectedExecutionException e) {
        Utils.E("RejectedExecutionException when download image", e);
      }
    }
  }

  /**
   * 下载产品详细页的截图
   */
  public static void downloadDeatilScreenshot(Context context, String url, ImageView imageView) {

    Session session = Session.get(context);
    if (session.isStopDownloadImage()) {
      return;
    }

    Drawable defaultDrawable = new BitmapDrawable();
    if (cancelPotentialBitmapDownload(url, imageView)) {
      BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
      DownloadedDrawable1 downloadedDrawable = new DownloadedDrawable1(defaultDrawable, task);
      imageView.setImageDrawable(downloadedDrawable);
      try {
        task.execute(context, url, TYPE_SCREENSHOT);
      } catch (RejectedExecutionException e) {
        Utils.E("RejectedExecutionException when download image", e);
      }
    }
  }

  /**
   * 下载产品详细页的截图
   */
  public static void downloadCpaImage(Context context, String url,
      ImageView imageView) {

    Session session = Session.get(context);
    if (session.isStopDownloadImage()) {
      return;
    }

    Drawable defaultDrawable = new BitmapDrawable();
    if (cancelPotentialBitmapDownload(url, imageView)) {
      BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
      DownloadedDrawable1 downloadedDrawable = new DownloadedDrawable1(defaultDrawable, task);
      imageView.setImageDrawable(downloadedDrawable);
      try {
        task.execute(context, url, TYPE_CPA);
      } catch (RejectedExecutionException e) {
        Utils.E("RejectedExecutionException when download image", e);
      }
    }
  }

  /**
   * 下载截图页的截图
   */
  public static void downloadScreenShot(Context context, String url, ImageView imageView) {

    Session session = Session.get(context);
    if (session.isStopDownloadImage()) {
      return;
    }

    AnimationDrawable loadingDrawable = new LoadingDrawable(context);
    if (cancelPotentialImageDownload(url, imageView)) {
      BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);

      DownloadedDrawable2 downloadedDrawable = new DownloadedDrawable2(loadingDrawable, task);
      // clear the old image
      imageView.setImageDrawable(null);
      imageView.setBackgroundDrawable(downloadedDrawable);
      downloadedDrawable.start();
      try {
        task.execute(context, url, TYPE_IMAGE);
      } catch (RejectedExecutionException e) {
        Utils.E("RejectedExecutionException when download image", e);
      }
    }
  }

  private static boolean cancelPotentialBitmapDownload(String url, ImageView imageView) {
    BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask1(imageView);

    if (bitmapDownloaderTask != null) {
      String bitmapUrl = bitmapDownloaderTask.url;
      if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
        bitmapDownloaderTask.cancel(true);
      } else {
        // The same URL is already being downloaded.
        return false;
      }
    }
    return true;
  }

  private static boolean cancelPotentialImageDownload(String url, ImageView imageView) {
    BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask2(imageView);

    if (bitmapDownloaderTask != null) {
      String bitmapUrl = bitmapDownloaderTask.url;
      if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
        bitmapDownloaderTask.cancel(true);
      } else {
        // The same URL is already being downloaded.
        return false;
      }
    }
    return true;
  }

  /**
   * 获得首页顶部推荐的图（按下效果）
   */

  public static StateListDrawable getMaskDrawable(Context context) {
    StateListDrawable stateDrawable = new StateListDrawable();
    int statePressed = android.R.attr.state_pressed;
    final Resources res = context.getResources();
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inPurgeable = true;
    o.inInputShareable = true;
    stateDrawable.addState(
        new int[] { statePressed },
        new BitmapDrawable(res, BitmapFactory
            .decodeResource(res, R.drawable.banner_pressed, o)));
    return stateDrawable;
  }

  private static Bitmap createUserIcon(Context context, Bitmap bmp) {

    float density = context.getResources().getDisplayMetrics().density;
    int vWidth = (int) (48 * density);
    int vHeight = vWidth;

    int dWidth = bmp.getWidth();
    int dHeight = bmp.getHeight();

    float scale;
    float dx = 0, dy = 0;

    if (dWidth * vHeight > vWidth * dHeight) {
      scale = (float) vHeight / (float) dHeight;
      dx = (vWidth - dWidth * scale) * 0.5f;
    } else {
      scale = (float) vWidth / (float) dWidth;
      dy = (vHeight - dHeight * scale) * 0.5f;
    }

    Bitmap src = Bitmap.createBitmap(vWidth, vWidth,
        Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(src);
    Matrix mDrawMatrix = new Matrix();
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mDrawMatrix.setScale(scale, scale);
    mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

    canvas.drawBitmap(bmp, mDrawMatrix, paint);

    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inPurgeable = true;
    o.inInputShareable = true;
    Bitmap mask = BitmapFactory.decodeResource(context.getResources(),
        R.drawable.default_user_mask, o);
    paint.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP));
    canvas.drawBitmap(mask, 0, 0, paint);

    Bitmap mask2 = BitmapFactory.decodeResource(context.getResources(),
        R.drawable.default_user_mask2, o);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OVER));
    canvas.drawBitmap(mask2, 0, 0, paint);
    canvas.save();

    return src;
  }

  /**
   * 创建首页推荐头像
   */
  public static Bitmap createHomeUserIcon(Context context, Bitmap bmp) {

    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inPurgeable = true;
    o.inInputShareable = true;

    float desity = context.getResources().getDisplayMetrics().density;
    int vwidth = (int) (48 * desity);
    int vheight = vwidth;

    int dwidth = bmp.getWidth();
    int dheight = bmp.getHeight();

    float scale;
    float dx = 0, dy = 0;

    if (dwidth * vheight > vwidth * dheight) {
      scale = (float) vheight / (float) dheight;
      dx = (vwidth - dwidth * scale) * 0.5f;
    } else {
      scale = (float) vwidth / (float) dwidth;
      dy = (vheight - dheight * scale) * 0.5f;
    }

    Bitmap src = Bitmap.createBitmap(vwidth, vwidth, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(src);
    Matrix mDrawMatrix = new Matrix();
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mDrawMatrix.setScale(scale, scale);
    mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
    canvas.drawBitmap(bmp, mDrawMatrix, paint);

    Bitmap mask = BitmapFactory.decodeResource(context.getResources(),
        R.drawable.default_user_mask, o);
    paint.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP));
    canvas.drawBitmap(mask, 0, 0, paint);

    int destWidth = (int) (60 * desity);
    int startPos = (int) (6 * desity);
    Bitmap destBmp = Bitmap.createBitmap(destWidth, destWidth, Bitmap.Config.ARGB_8888);
    canvas = new Canvas(destBmp);

    canvas.drawBitmap(src, startPos, startPos, paint);

    Bitmap mask2 = BitmapFactory.decodeResource(context.getResources(),
        R.drawable.home_gallery_user_mask, o);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OVER));
    canvas.drawBitmap(mask2, 0, 0, paint);
    canvas.save();

    return destBmp;
  }
  
  /**
   * @unused 暂时不使用Icon上绘制角标
   */
  public static Bitmap maskCorner(Context context,Bitmap src,CornerMark mark){
      
      if(mark == null || mark.isEmpty()){
          return src;
      }
      
      //图片标准 
      //54dp * 54dp
      float density = context.getResources().getDisplayMetrics().density;
      
      int width  = (int) (54 * density);
      int height = width;
      
      if(width <= 0 || height <= 0){
          Utils.E("can't get density! " +
                "method'maskCorner(Context,Bitmap,CornerMark)'");
          return src;
      }
      
      Bitmap corner = BitmapFactory.decodeResource(context.getResources(),
              mark.getResId());
      
      Bitmap _src    = Bitmap.createScaledBitmap(src, width, height, true);
      Bitmap _corner = Bitmap.createScaledBitmap(corner, 
              //0.6 为 角标占总icon的多大
              (int) (width * 0.6), (int) (height * 0.6), true);
      
      Paint paint = new Paint();
      
      //创建空白的Bitmap
      Bitmap result = Bitmap.createBitmap(width, height, Config.ARGB_8888);
      
      Canvas canvas = new Canvas(result);
      canvas.drawBitmap(_src, 0, 0, paint);
      canvas.drawBitmap(_corner, 0, 0, paint);
      
      return result;
  }

  /**
   * 对暂停下载的图标进行遮罩处理
   */
  public static Bitmap maskPauseIcon(Context context, Bitmap src) {

    float density = context.getResources().getDisplayMetrics().density;
    int iconSize = (int) (48 * density);
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inPurgeable = true;
    o.inInputShareable = true;
    int targetDensity = context.getResources().getDisplayMetrics().densityDpi;
    o.inTargetDensity = targetDensity;

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Bitmap targetBitmap = Bitmap.createBitmap(iconSize, iconSize,
        Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(targetBitmap);

    float scale = iconSize / (float) src.getWidth();
    final Bitmap oldBitmap = src;
    Bitmap bm = Bitmap.createScaledBitmap(oldBitmap,
        (int) (src.getWidth() * scale + 0.5f),
        (int) (src.getHeight() * scale + 0.5f), true);
    bm.setDensity(targetDensity);
    canvas.drawBitmap(bm, 0, 0, paint);

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OVER));

    // 绘制半透明遮罩
    Bitmap mask = BitmapFactory.decodeResource(context.getResources(),
        R.drawable.pause_mask, o);
    canvas.drawBitmap(mask, 0, 0, paint);

    // 绘制暂停按钮
    Bitmap pause = BitmapFactory.decodeResource(context.getResources(),
        R.drawable.pause, o);
    int margin = (iconSize - pause.getWidth()) / 2;
    canvas.drawBitmap(pause, margin, margin, paint);
    return targetBitmap;
  }

  /**
   * 通过图片长宽比判断是否需要旋转处理
   */

  public static Bitmap rotateImage(int ww, int hh, Bitmap bmp) {

    if (bmp == null)
      return bmp;

    int width = bmp.getWidth();
    int height = bmp.getHeight();
    float aspectRatio = ((float) height) / width;

    if (aspectRatio < 1) {
      // 旋转图片
      Matrix matrix = new Matrix();
      matrix.postRotate(90);
      bmp = Bitmap.createBitmap(bmp, 0, 0, height, width, matrix, false);
      width = bmp.getWidth();
      height = bmp.getHeight();
    }
    float zoomRatio = (float) hh / (float) height;
    int screenWidth = (int) (width * zoomRatio);

    Bitmap rotatedBitmap = null;
    try {
      rotatedBitmap = Bitmap.createScaledBitmap(bmp, screenWidth, hh, false);
    } catch (OutOfMemoryError e) {
    }
    return rotatedBitmap;
  }

  /**
   * 通过图片长宽比判断是否需要旋转处理
   */

  public static Bitmap rotateImage(Bitmap bmp) {

    if (bmp == null)
      return bmp;

    int width = bmp.getWidth();
    int height = bmp.getHeight();
    float aspectRatio = ((float) height) / width;

    if (aspectRatio > 1) {
      // no need to rotate the image
      return bmp;
    }

    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    Bitmap rotatedBitmap = null;
    try {
      rotatedBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, false);
    } catch (OutOfMemoryError e) {
    }
    return rotatedBitmap;
  }

  /**
   * 获取适应屏幕大小的图
   */

  public static Bitmap scaleBitmap(Context context, Bitmap bitmap) {

    if (bitmap == null) {
      return null;
    }

    // 适配屏幕大小
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    int screenWidth = metrics.widthPixels;
    float aspectRatio = (float) screenWidth / (float) width;
    int scaledHeight = (int) (height * aspectRatio);
    Bitmap scaledBitmap = null;
    try {
      scaledBitmap = Bitmap.createScaledBitmap(bitmap, screenWidth, scaledHeight, true);
    } catch (OutOfMemoryError e) {
    }
    return scaledBitmap;
  }

  /**
   * 将Bitmap缓存到cache
   */
  public static void saveBitmapToSdcard(Context context, String key, Bitmap bmp) {

    final File cacheDir = context.getCacheDir();
    FileOutputStream fos = null;
    try {
      fos = new FileOutputStream(new File(cacheDir, String.valueOf(key)));
      bmp.compress(CompressFormat.PNG, 100, fos);
    } catch (FileNotFoundException e) {
      Utils.E("Error when save bitmap to sdcard", e);
    } finally {
      Utils.closeStreamSilently(fos);
    }
  }

  /**
   * 将Bitmap缓存到file
   */
  public static void saveBitmapToFile(Context context, String key, Bitmap bmp) {

    final File cacheDir = context.getFilesDir();

    // 避免重复缓存
    for (String fileName : cacheDir.list()) {

      int splitterPos = fileName.lastIndexOf(".");
      if (splitterPos < 0) {
        continue;
      }
      String name = fileName.substring(0, splitterPos);
      if (name.startsWith(String.valueOf(key))) {
        return;
      }
    }

    FileOutputStream fos = null;
    try {
      fos = new FileOutputStream(new File(cacheDir, String.valueOf(key)));
      bmp.compress(CompressFormat.PNG, 100, fos);
    } catch (FileNotFoundException e) {
      Utils.E("Error when save bitmap to sdcard", e);
    } finally {
      Utils.closeStreamSilently(fos);
    }
  }

  /**
   * 从SdCard获取缓存图片，如果不存在返回Null
   */

  public static Bitmap getBitmapFromSdcard(Context context, String url, boolean isCompress) {

    final File cacheDir = context.getCacheDir();
    String fileName = CacheManager.getInstance(context).getFileName(url);
    if (fileName == null) {
      return null;
    }

    final File imageFile = new File(cacheDir, fileName);
    if (imageFile.exists()) {
      try {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inPurgeable = true;
        o.inInputShareable = true;
        if (isCompress) {
          o.inSampleSize = 2;
        }
        return BitmapFactory.decodeFile(imageFile.getAbsolutePath(), o);
      } catch (OutOfMemoryError e) {
        Utils.E("decode bitmap from sdcard error", e);
      }
    }
    return null;
  }


  public static Bitmap getDrawableFromFile(Context context, String url) {

    final File fileDir = context.getFilesDir();
    final int key = url.hashCode();

    Bitmap bmp = null;
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inPurgeable = true;
    o.inInputShareable = true;
    for (String fileName : fileDir.list()) {

      int splitterPos = fileName.lastIndexOf(".");
      if (splitterPos < 0) {
        continue;
      }
      String name = fileName.substring(0, splitterPos);
      String extension = fileName.substring(splitterPos + 1);
      long expire = Utils.getLong(extension);

      if (expire > 0 && expire < System.currentTimeMillis()) {
        new File(fileDir, fileName).delete();
        continue;
      }

      if (name.startsWith(String.valueOf(key))) {
        final File imageFile = new File(fileDir, fileName);
        try {
          bmp = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), o);
        } catch (OutOfMemoryError e) {
          Utils.E("decode bitmap from sdcard error", e);
        }
      }
    }
    return bmp;
  }
}

class FlushedInputStream extends FilterInputStream {
  public FlushedInputStream(InputStream inputStream) {
    super(inputStream);
  }

  @Override
  public long skip(long n) throws IOException {
    long totalBytesSkipped = 0L;
    while (totalBytesSkipped < n) {
      long bytesSkipped = in.skip(n - totalBytesSkipped);
      if (bytesSkipped == 0L) {
        int byteRead = read();
        if (byteRead < 0) {
          break; // we reached EOF
        } else {
          bytesSkipped = 1; // we read one byte
        }
      }

      totalBytesSkipped += bytesSkipped;
    }
    return totalBytesSkipped;
  }
}
